/*****************************************************************************
 * Copyright (C) Stacy Curl. All rights reserved.                            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *****************************************************************************/
package picounit.impl;

import org.picocontainer.MutablePicoContainer;

import picounit.Implementation;
import picounit.Interface;
import picounit.Registry;
import picounit.features.classloader.ClassReloader;
import picounit.features.registry.RegistryEntries;
import picounit.features.registry.RegistryImpl;
import picounit.features.registry.Resolver;
import picounit.features.registry.TypeFactory;
import picounit.features.registry.RegistryImpl.PicoContainerInstantiator;
import previous.picounit.TestCase;

public class RegistryTest extends TestCase {
	private MutablePicoContainer picoContainer;

	public static class SomeClass{}
	public static class AnotherClass{}

	private RegistryEntries registryEntries;
	private ClassReloader classReloader;
	private Registry registry;
	private Resolver resolver;
	private TypeFactory typeFactory;

	public void mock(MutablePicoContainer picoContainer, PicoContainerInstantiator picoContainerInstantiator,
		RegistryEntries registryEntries, ClassReloader classReloader, TypeFactory typeFactory) {
		
		RegistryImpl registry =
			new RegistryImpl(picoContainer, picoContainerInstantiator, registryEntries, classReloader, typeFactory);
		
		this.registry = registry;
		this.resolver = registry;

		this.picoContainer = picoContainer;
		this.registryEntries = registryEntries;
		this.classReloader = classReloader;
		this.typeFactory = typeFactory;
	}

	public void shouldDelegateInstanceRegistrationToPico() {
		Class<SomeClass> key = SomeClass.class;
		SomeClass value = new SomeClass();
		
		should.call(classReloader.reloadClass(key))
			.andReturn(key);

		shouldCall:
			registryEntries.register(key, value);
			picoContainer.registerComponentInstance(key, value); 

		should.expectAboveWhenTheFollowingOccurs();

		registry.register(key, value);
	}
	
	public void shouldDelegateInterfaceToImplementationRegistrationToPico() {
		should.call(classReloader.reloadClass(Interface.class))
			.andReturn(Interface.class);
		should.call(classReloader.reloadClass(Implementation.class))
			.andReturn(Implementation.class);

		shouldCall:
			registryEntries.register(Interface.class, Implementation.class);
			picoContainer.registerComponentImplementation(Interface.class, Implementation.class);

		should.expectAboveWhenTheFollowingOccurs();

		registry.register(Interface.class, Implementation.class);
	}
	
	public void shouldDelegateImplementationRegistrationToPico() {
		should.call(classReloader.reloadClass(Implementation.class))
			.andReturn(Implementation.class);

		shouldCall:
			registryEntries.register(Implementation.class);
			picoContainer.registerComponentImplementation(Implementation.class);

		should.expectAboveWhenTheFollowingOccurs();

		registry.register(Implementation.class);
	}
	
	public void shouldDelegateConstantStringRegistrationToPico() {
		shouldCall:
			registryEntries.register("key", "value");
			picoContainer.registerComponentInstance("key", "value");

		should.expectAboveWhenTheFollowingOccurs();

		registry.register("key", "value");
	}
	
	public void shouldDelegateConstantPrimativeBooleanRegistrationToPicoByWrappingWithBoolean() {
		shouldCall:
			registryEntries.register("key", true);
			picoContainer.registerComponentInstance("key", Boolean.TRUE);

		should.expectAboveWhenTheFollowingOccurs();

		registry.register("key", true);
	}
	
	public void shouldDelegateConstantPrimativeByteRegistrationToPicoByWrappingWithByte() {
		shouldCall:
			registryEntries.register("key", (byte) 0xAB);
			picoContainer.registerComponentInstance("key", new Byte((byte) 0xAB));

		should.expectAboveWhenTheFollowingOccurs();

		registry.register("key", (byte) 0xAB);
	}

	public void shouldDelegateConstantPrimativeCharRegistrationToPicoByWrappingWithCharacter() {
		shouldCall:
			registryEntries.register("key", 'c');
			picoContainer.registerComponentInstance("key", new Character('c'));

		should.expectAboveWhenTheFollowingOccurs();

		registry.register("key", 'c');
	}
	
	public void shouldDelegateConstantPrimativeDoubleRegistrationToPicoByWrappingWithDouble() {
		shouldCall:
			registryEntries.register("key", 123.456);
			picoContainer.registerComponentInstance("key", new Double(123.456));

		should.expectAboveWhenTheFollowingOccurs();

		registry.register("key", 123.456);
	}

	public void shouldDelegateConstantPrimativeFloatRegistrationToPicoByWrappingWithFloat() {
		shouldCall:
			registryEntries.register("key", 123.456f);
			picoContainer.registerComponentInstance("key", new Float(123.456));

		should.expectAboveWhenTheFollowingOccurs();

		registry.register("key", 123.456f);
	}
	
	public void shouldDelegateConstantPrimativeIntRegistrationToPicoByWrappingWithInteger() {
		shouldCall:
			registryEntries.register("key", 123);
			picoContainer.registerComponentInstance("key", new Integer(123));

		should.expectAboveWhenTheFollowingOccurs();

		registry.register("key", 123);
	}
	
	public void shouldDelegateConstantPrimativeLongRegistrationToPicoByWrappingWithLong() {
		shouldCall:
			registryEntries.register("key", (long) 123456789);
			picoContainer.registerComponentInstance("key", new Long(123456789));

		should.expectAboveWhenTheFollowingOccurs();

		registry.register("key", (long) 123456789);
	}

	public void shouldDelegateConstantPrimativeShortRegistrationToPicoByWrappingWithShort() {
		shouldCall:
			registryEntries.register("key", (short) 123);
			picoContainer.registerComponentInstance("key", new Short((short) 123));

		should.expectAboveWhenTheFollowingOccurs();

		registry.register("key", (short) 123);
	}
	
	public void shouldDoSomethingWithAFactory() {
		Implementation implementation = new Implementation();

		should.call(typeFactory.hasInstance(Interface.class))
			.andReturn(true);

		should.call(typeFactory.getInstance(Interface.class))
			.andReturn(implementation);
		
		should.expectAboveWhenTheFollowingOccurs();

		registry.registerFactory(Interface.class)
			.add(implementation)
			.done();

		verify.that(resolver.get("name", Interface.class))
			.isTheSameAs(implementation);
	}
}
